home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / utils / shell / cdialog-.9a / cdialog- / cdialog-0.9a / textbox.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-15  |  24.1 KB  |  788 lines

  1. /*
  2.  *  textbox.c -- implements the text box
  3.  *
  4.  *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
  5.  *
  6.  *  This program is free software; you can redistribute it and/or
  7.  *  modify it under the terms of the GNU General Public License
  8.  *  as published by the Free Software Foundation; either version 2
  9.  *  of the License, or (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21.  
  22. #include "dialog.h"
  23.  
  24.  
  25. static void back_lines(int n);
  26. static void print_page(WINDOW *win, int height, int width);
  27. static void print_line(WINDOW *win, int row, int width);
  28. static char *get_line(void);
  29. static int get_search_term(WINDOW *win, char *search_term, int height, int width);
  30. static void print_position(WINDOW *win, int height, int width);
  31. static char *read_high(int fd, char *buf, size_t size_read);
  32. static int tabize(int val, int pos);
  33.  
  34. static int hscroll = 0, fd, file_size, bytes_read, begin_reached = 1,
  35.            end_reached = 0, page_length, buffer_len = 0, buffer_first = 1,
  36.            fd_bytes_read;
  37. char *buf, *page;
  38.  
  39.  
  40. /*
  41.  * Display text from a file in a dialog box.
  42.  */
  43. int dialog_textbox(const char *title, const char *file, int height, int width)
  44. {
  45.   int i, x, y, cur_x, cur_y, fpos, key = 0, dir, temp, temp1;
  46. #ifdef HAVE_NCURSES
  47.   int passed_end;
  48. #endif
  49.   char search_term[MAX_LEN+1], *tempptr, *found;
  50.   WINDOW *dialog, *text;
  51.  
  52.   auto_sizefile(file, &height, &width, 2, 12);
  53.   print_size(height, width);
  54.   ctl_size(height, width);
  55.  
  56.   search_term[0] = '\0';    /* no search term entered yet */
  57.  
  58.   /* Open input file for reading */
  59.   if ((fd = open(file, O_RDONLY)) == -1)
  60.     exiterr("\nCan't open input file in dialog_textbox().\n");
  61.  
  62.   /* Get file size. Actually, 'file_size' is the real file size - 1,
  63.      since it's only the last byte offset from the beginning */
  64.   if ((file_size = lseek(fd, 0, SEEK_END)) == -1)
  65.     exiterr("\nError getting file size in dialog_textbox().\n");
  66.  
  67.   /* Restore file pointer to beginning of file after getting file size */
  68.   if (lseek(fd, 0, SEEK_SET) == -1)
  69.     exiterr("\nError moving file pointer in dialog_textbox().\n");
  70.  
  71.   if ((buf = read_high(fd, buf, BUF_SIZE)) == NULL)
  72.     exiterr("\nError reading file in dialog_textbox().\n");
  73.  
  74.   page = buf;    /* page is pointer to start of page to be displayed */
  75.  
  76.   if (begin_set == 1) {
  77.     x = begin_x;
  78.     y = begin_y;
  79.   } else {
  80.     /* center dialog box on screen */
  81.     x = (SCOLS - width)/2;
  82.     y = (SLINES - height)/2;
  83.   }
  84.  
  85. #ifdef HAVE_NCURSES
  86.   if (use_shadow)
  87.     draw_shadow(stdscr, y, x, height, width);
  88. #endif
  89.   dialog = newwin(height, width, y, x);
  90.   mouse_setbase (x, y);
  91.   keypad(dialog, TRUE);
  92.  
  93.   /* Create window for text region, used for scrolling text */
  94.   text = subwin(dialog, height-4, width-2, y+1, x+1);
  95.  
  96.   keypad (text, TRUE);
  97.  
  98.   /* register the new window, along with its borders */
  99.   mouse_mkbigregion (0, 0, height - 2, width, 1, 0, 2 /* not normal */ );
  100.   draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
  101.  
  102.   wattrset(dialog, border_attr);
  103.   wmove(dialog, height-3, 0);
  104.   waddch(dialog, ACS_LTEE);
  105.   for (i = 0; i < width-2; i++)
  106.     waddch(dialog, ACS_HLINE);
  107.   wattrset(dialog, dialog_attr);
  108.   waddch(dialog, ACS_RTEE);
  109.   wmove(dialog, height-2, 1);
  110.   for (i = 0; i < width-2; i++)
  111.     waddch(dialog, ' ');
  112.  
  113.   if (title != NULL) {
  114.     wattrset(dialog, title_attr);
  115.     wmove(dialog, 0, (width - strlen(title))/2 - 1);
  116.     waddch(dialog, ' ');
  117.     waddstr(dialog, title);
  118.     waddch(dialog, ' ');
  119.   }
  120.   print_button(dialog, " EXIT ", height-2, width/2-4, TRUE);
  121.   wnoutrefresh(dialog);
  122.   getyx(dialog, cur_y, cur_x);    /* Save cursor position */
  123.  
  124.   /* Print first page of text */
  125.   attr_clear(text, height-4, width-2, dialog_attr);
  126.   print_page(text, height-4, width-2);
  127.   print_position(dialog, height, width);
  128.   wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
  129.   wrefresh_lock(dialog);
  130.   wtimeout(dialog, WTIMEOUT_VAL);
  131.  
  132.   while (key != ESC) {
  133.     key = mouse_wgetch(dialog);
  134.     switch (key) {
  135.       case M_EVENT + 'E':
  136.       case 'E':            /* Exit */
  137.       case 'e':
  138.       case '\n':
  139.         delwin(dialog);
  140.         free(buf);
  141.         close(fd);
  142.         return 0;
  143.       case 'g':    /* First page */
  144.       case KEY_HOME:
  145.         if (!begin_reached) {
  146.           begin_reached = 1;
  147.           /* First page not in buffer? */
  148.           if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1)
  149.             exiterr("\nError moving file pointer in dialog_textbox().\n");
  150.  
  151.           if (fpos > fd_bytes_read) {    /* Yes, we have to read it in */
  152.             if (lseek(fd, 0, SEEK_SET) == -1)
  153.               exiterr("\nError moving file pointer in dialog_textbox().\n");
  154.  
  155.             if ((buf = read_high(fd, buf, BUF_SIZE)) == NULL)
  156.               exiterr("\nError reading file in dialog_textbox().\n");
  157.           }
  158.           page = buf;
  159.           print_page(text, height-4, width-2);
  160.           print_position(dialog, height, width);
  161.           wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
  162.           wrefresh_lock(dialog);
  163.         }
  164.         break;
  165.       case 'G':    /* Last page */
  166. #ifdef HAVE_NCURSES
  167.       case KEY_END:
  168. #endif
  169.         end_reached = 1;
  170.         /* Last page not in buffer? */
  171.         if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1)
  172.           exiterr("\nError moving file pointer in dialog_textbox().\n");
  173.  
  174.         if (fpos < file_size) {    /* Yes, we have to read it in */
  175.           if (lseek(fd, -BUF_SIZE, SEEK_END) == -1)
  176.             exiterr("\nError moving file pointer in dialog_textbox().\n");
  177.  
  178.           if ((buf = read_high(fd, buf, BUF_SIZE)) == NULL)
  179.             exiterr("\nError reading file in dialog_textbox().\n");
  180.         }
  181.         page = buf + bytes_read;
  182.         back_lines(height-4);
  183.         print_page(text, height-4, width-2);
  184.         print_position(dialog, height, width);
  185.         wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
  186.         wrefresh_lock(dialog);
  187.         break;
  188.       case 'K':    /* Previous line */
  189.       case 'k':
  190.       case KEY_UP:
  191.         if (!begin_reached) {
  192.           back_lines(page_length+1);
  193. #ifdef HAVE_NCURSES
  194.           /* We don't call print_page() here but use scrolling to ensure
  195.              faster screen update. However, 'end_reached' and 'page_length'
  196.              should still be updated, and 'page' should point to start of
  197.              next page. This is done by calling get_line() in the following
  198.              'for' loop. */
  199.           scrollok(text, TRUE);
  200.           wscrl(text, -1);    /* Scroll text region down one line */
  201.           scrollok(text, FALSE);
  202.           page_length = 0;
  203.           passed_end = 0;
  204.           for (i = 0; i < height-4; i++) {
  205.             if (!i) {
  206.               print_line(text, 0, width-2);    /* print first line of page */
  207.               wnoutrefresh(text);
  208.             }
  209.             else
  210.               get_line();    /* Called to update 'end_reached' and 'page' */
  211.             if (!passed_end)
  212.               page_length++;
  213.             if (end_reached && !passed_end)
  214.               passed_end = 1;
  215.           }
  216. #else
  217.           print_page(text, height-4, width-2);
  218. #endif
  219.           print_position(dialog, height, width);
  220.           wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
  221.           wrefresh_lock(dialog);
  222.         }
  223.         break;
  224.       case 'B':    /* Previous page */
  225.       case 'b':
  226.       case KEY_PPAGE:
  227.         if (!begin_reached) {
  228.           back_lines(page_length + height-4);
  229.           print_page(text, height-4, width-2);
  230.           print_position(dialog, height, width);
  231.           wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
  232.           wrefresh_lock(dialog);
  233.         }
  234.         break;
  235.       case 'J':    /* Next line */
  236.       case 'j':
  237.       case KEY_DOWN:
  238.         if (!end_reached) {
  239.           begin_reached = 0;
  240.           scrollok(text, TRUE);
  241.           scroll(text);    /* Scroll text region up one line */
  242.           scrollok(text, FALSE);
  243.           print_line(text, height-5, width-2);
  244. #ifndef HAVE_NCURSES
  245.           wmove(text, height-5, 0);
  246.           waddch(text, ' ');
  247.           wmove(text, height-5, width-3);
  248.           waddch(text, ' ');
  249. #endif
  250.           wnoutrefresh(text);
  251.           print_position(dialog, height, width);
  252.           wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
  253.           wrefresh_lock(dialog);
  254.         }
  255.         break;
  256.       case ' ':    /* Next page */
  257.       case KEY_NPAGE:
  258.         if (!end_reached) {
  259.           begin_reached = 0;
  260.           print_page(text, height-4, width-2);
  261.           print_position(dialog, height, width);
  262.           wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
  263.           wrefresh_lock(dialog);
  264.         }
  265.         break;
  266.       case '0':    /* Beginning of line */
  267.       case 'H':    /* Scroll left */
  268.       case 'h':
  269.       case KEY_LEFT:
  270.         if (hscroll > 0) {
  271.           if (key == '0')
  272.             hscroll = 0;
  273.           else
  274.             hscroll--;
  275.           /* Reprint current page to scroll horizontally */
  276.           back_lines(page_length);
  277.           print_page(text, height-4, width-2);
  278.           wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
  279.           wrefresh_lock(dialog);
  280.         }
  281.         break;
  282.       case 'L':    /* Scroll right */
  283.       case 'l':
  284.       case KEY_RIGHT:
  285.         if (hscroll < MAX_LEN) {
  286.           hscroll++;
  287.           /* Reprint current page to scroll horizontally */
  288.           back_lines(page_length);
  289.           print_page(text, height-4, width-2);
  290.           wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
  291.           wrefresh_lock(dialog);
  292.         }
  293.         break;
  294.       case '/':    /* Forward search */
  295.       case 'n':    /* Repeat forward search */
  296.       case '?':    /* Backward search */
  297.       case 'N':    /* Repeat backward search */
  298.         /* set search direction */
  299.         dir = (key == '/' || key == 'n') ? 1 : 0;
  300.         if (dir ? !end_reached : !begin_reached) {
  301.           if (key == 'n' || key == 'N') {
  302.             if (search_term[0] == '\0') {    /* No search term yet */
  303.               fprintf(stderr, "\a");    /* beep */
  304.               break;
  305.             }
  306.       }
  307.           else    /* Get search term from user */
  308.             if (get_search_term(text, search_term, height-4, width-2) == -1) {
  309.               /* ESC pressed in get_search_term(). Reprint page to clear box */
  310.               wattrset(text, dialog_attr);
  311.               back_lines(page_length);
  312.               print_page(text, height-4, width-2);
  313.               wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
  314.               wrefresh_lock(dialog);
  315.               break;
  316.             }
  317.           /* Save variables for restoring in case search term can't be found */
  318.           tempptr = page;
  319.           temp = begin_reached;
  320.           temp1 = end_reached;
  321.           if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1)
  322.             exiterr("\nError moving file pointer in dialog_textbox().\n");
  323.  
  324.           fpos -= fd_bytes_read;
  325.           /* update 'page' to point to next (previous) line before
  326.              forward (backward) searching */
  327.           back_lines(dir ? page_length-1 : page_length+1);
  328.           found = NULL;
  329.           if (dir)    /* Forward search */
  330.             while((found = strstr(get_line(), search_term)) == NULL) {
  331.               if (end_reached)
  332.                 break;
  333.         }
  334.           else    /* Backward search */
  335.             while((found = strstr(get_line(), search_term)) == NULL) {
  336.               if (begin_reached)
  337.                 break;
  338.               back_lines(2);
  339.             }
  340.           if (found == NULL) {    /* not found */
  341.             fprintf(stderr, "\a");    /* beep */
  342.             /* Restore program state to that before searching */
  343.             if (lseek(fd, fpos, SEEK_SET) == -1)
  344.               exiterr("\nError moving file pointer in dialog_textbox().\n");
  345.  
  346.             if ((buf = read_high(fd, buf, BUF_SIZE)) == NULL)
  347.               exiterr("\nError reading file in dialog_textbox().\n");
  348.  
  349.             page = tempptr;
  350.             begin_reached = temp;
  351.             end_reached = temp1;
  352.             /* move 'page' to point to start of current page in order to
  353.                re-print current page. Note that 'page' always points to
  354.                start of next page, so this is necessary */
  355.             back_lines(page_length);
  356.           }
  357.           else    /* Search term found */
  358.             back_lines(1);
  359.           /* Reprint page */
  360.           wattrset(text, dialog_attr);
  361.           print_page(text, height-4, width-2);
  362.           if (found != NULL)
  363.             print_position(dialog, height, width);
  364.           wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
  365.           wrefresh_lock(dialog);
  366.         }
  367.         else    /* no need to find */
  368.           fprintf(stderr, "\a");    /* beep */
  369.         break;
  370.       case ESC:
  371.         break;
  372.     }
  373.   }
  374.  
  375.   delwin(dialog);
  376.   free(buf);
  377.   close(fd);
  378.   return -1;    /* ESC pressed */
  379. }
  380. /* End of dialog_textbox() */
  381.  
  382.  
  383. /*
  384.  * Go back 'n' lines in text file. Called by dialog_textbox().
  385.  * 'page' will be updated to point to the desired line in 'buf'.
  386.  */
  387. static void back_lines(int n)
  388. {
  389.   int i, fpos, val_to_tabize;
  390.  
  391.   begin_reached = 0;
  392.   /* We have to distinguish between end_reached and !end_reached since at end
  393.      of file, the line is not ended by a '\n'. The code inside 'if' basically
  394.      does a '--page' to move one character backward so as to skip '\n' of the
  395.      previous line */
  396.   if (!end_reached) {
  397.     /* Either beginning of buffer or beginning of file reached? */
  398.  
  399.     if (page == buf) {
  400.       if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1)
  401.         exiterr("\nError moving file pointer in back_lines().\n");
  402.  
  403.       if (fpos > fd_bytes_read) {    /* Not beginning of file yet */
  404.         /* We've reached beginning of buffer, but not beginning of file yet,
  405.            so read previous part of file into buffer. Note that we only
  406.            move backward for BUF_SIZE/2 bytes, but not BUF_SIZE bytes to
  407.            avoid re-reading again in print_page() later */
  408.         /* Really possible to move backward BUF_SIZE/2 bytes? */
  409.         if (fpos < BUF_SIZE/2 + fd_bytes_read) {
  410.           /* No, move less then */
  411.           if (lseek(fd, 0, SEEK_SET) == -1)
  412.             exiterr("\nError moving file pointer in back_lines().\n");
  413.  
  414.           val_to_tabize = fpos - fd_bytes_read;
  415.         }
  416.         else {    /* Move backward BUF_SIZE/2 bytes */
  417.           if (lseek(fd, -(BUF_SIZE/2 + fd_bytes_read), SEEK_CUR) == -1)
  418.             exiterr("\nError moving file pointer in back_lines().\n");
  419.  
  420.           val_to_tabize = BUF_SIZE/2;
  421.         }
  422.         if ((buf = read_high(fd, buf, BUF_SIZE)) == NULL)
  423.           exiterr("\nError reading file in back_lines().\n");
  424.  
  425.         page = buf + tabize(val_to_tabize, 0);
  426.         
  427.       }
  428.       else {    /* Beginning of file reached */
  429.         begin_reached = 1;
  430.         return;
  431.       }
  432.     }
  433.     if (*(--page) != '\n')    /* '--page' here */ /* Something's wrong... */
  434.       exiterr("\nInternal error in back_lines().\n");
  435.   }
  436.  
  437.   /* Go back 'n' lines */
  438.   for (i = 0; i < n; i++)
  439.     do {
  440.       if (page == buf) {
  441.         if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1)
  442.           exiterr("\nError moving file pointer in back_lines().\n");
  443.  
  444.         if (fpos > fd_bytes_read) {
  445.           /* Really possible to move backward BUF_SIZE/2 bytes? */
  446.           if (fpos < BUF_SIZE/2 + fd_bytes_read) {
  447.             /* No, move less then */
  448.             if (lseek(fd, 0, SEEK_SET) == -1)
  449.               exiterr("\nError moving file pointer in back_lines().\n");
  450.  
  451.             val_to_tabize = fpos - fd_bytes_read;
  452.           }
  453.           else {    /* Move backward BUF_SIZE/2 bytes */
  454.             if (lseek(fd, -(BUF_SIZE/2 + fd_bytes_read), SEEK_CUR) == -1)
  455.               exiterr("\nError moving file pointer in back_lines().\n");
  456.  
  457.             val_to_tabize = BUF_SIZE/2;
  458.           }
  459.           if ((buf = read_high(fd, buf, BUF_SIZE)) == NULL)
  460.             exiterr("\nError reading file in back_lines().\n");
  461.             
  462.           page = buf + tabize(val_to_tabize, 0);
  463.  
  464.         }
  465.         else {    /* Beginning of file reached */
  466.           begin_reached = 1;
  467.           return;
  468.         }
  469.       }
  470.     } while (*(--page) != '\n');
  471.   page++;
  472. }
  473. /* End of back_lines() */
  474.  
  475.  
  476. /*
  477.  * Print a new page of text. Called by dialog_textbox().
  478.  */
  479. static void print_page(WINDOW *win, int height, int width)
  480. {
  481.   int i, passed_end = 0;
  482.  
  483.   page_length = 0;
  484.   for (i = 0; i < height; i++) {
  485.     print_line(win, i, width);
  486.     if (!passed_end)
  487.       page_length++;
  488.     if (end_reached && !passed_end)
  489.       passed_end = 1;
  490.   }
  491.   wnoutrefresh(win);
  492. }
  493. /* End of print_page() */
  494.  
  495.  
  496. /*
  497.  * Print a new line of text. Called by dialog_textbox() and print_page().
  498.  */
  499. static void print_line(WINDOW *win, int row, int width)
  500. {
  501.   int i, y, x;
  502.   char *line;
  503.   line = get_line();
  504.   line += MIN(strlen(line),hscroll);    /* Scroll horizontally */
  505.   wmove(win, row, 0);    /* move cursor to correct line */
  506.   waddch(win,' ');
  507. #ifdef HAVE_NCURSES
  508.   waddnstr(win, line, MIN(strlen(line),width-2));
  509. #else
  510.   line[MIN(strlen(line),width-2)] = '\0';
  511.   waddstr(win, line);
  512. #endif
  513.  
  514.   getyx(win, y, x);
  515.   /* Clear 'residue' of previous line */
  516.   for (i = 0; i < width-x; i++)
  517.     waddch(win, ' ');
  518. }
  519. /* End of print_line() */
  520.  
  521.  
  522. /*
  523.  * Return current line of text. Called by dialog_textbox() and print_line().
  524.  * 'page' should point to start of current line before calling, and will be
  525.  * updated to point to start of next line.
  526.  */
  527. static char *get_line(void)
  528. {
  529.   int i = 0, fpos;
  530.   static char line[MAX_LEN+1];
  531.  
  532.   end_reached = 0;
  533.   while (*page != '\n') {
  534.     if (*page == '\0') {    /* Either end of file or end of buffer reached */
  535.       if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1)
  536.         exiterr("\nError moving file pointer in get_line().\n");
  537.  
  538.       if (fpos < file_size) {    /* Not end of file yet */
  539.         /* We've reached end of buffer, but not end of file yet, so read next
  540.            part of file into buffer */
  541.         if ((buf = read_high(fd, buf, BUF_SIZE)) == NULL)
  542.           exiterr("\nError reading file in get_line().\n");
  543.         page = buf;
  544.       }
  545.       else {
  546.         if (!end_reached)
  547.           end_reached = 1;
  548.         break;
  549.       }
  550.     }
  551.     else
  552.       if (i < MAX_LEN)
  553.         line[i++] = *(page++);
  554.       else {
  555.         if (i == MAX_LEN)  /* Truncate lines longer than MAX_LEN characters */
  556.           line[i++] = '\0';
  557.         page++;
  558.       }
  559.   }
  560.   if (i <= MAX_LEN)
  561.     line[i] = '\0';
  562.   if (!end_reached)
  563.     page++;    /* move pass '\n' */
  564.  
  565.   return line;
  566. }
  567. /* End of get_line() */
  568.  
  569.  
  570. /*
  571.  * Display a dialog box and get the search term from user
  572.  */
  573. static int get_search_term(WINDOW *win, char *search_term, int height, int width)
  574. {
  575.   int i, x, y, input_x = 0, scroll = 0, key = 0,
  576.       box_height = 3, box_width = 30;
  577.  
  578.   x = (width - box_width)/2;
  579.   y = (height - box_height)/2;
  580. #ifdef HAVE_NCURSES
  581.   if (use_shadow)
  582.     draw_shadow(win, y, x, box_height, box_width);
  583. #endif
  584.   draw_box(win, y, x, box_height, box_width, dialog_attr, searchbox_border_attr);
  585.   wattrset(win, searchbox_title_attr);
  586.   wmove(win, y, x+box_width/2-4);
  587.   waddstr(win, " Search ");
  588.  
  589.   box_width -= 2;
  590.   wmove(win, y+1, x+1);
  591.   wrefresh_lock(win);
  592.   search_term[0] = '\0';
  593.   wattrset(win, searchbox_attr);
  594.   while (key != ESC) {
  595.     key = wgetch(win);
  596.     switch (key) {
  597.       case '\n':
  598.         if (search_term[0] != '\0')
  599.           return 0;
  600.         break;
  601.       case KEY_BACKSPACE:
  602.       case 127:
  603.         if (input_x || scroll) {
  604.           if (!input_x) {
  605.             scroll = scroll < box_width-1 ? 0 : scroll-(box_width-1);
  606.             wmove(win, y+1, x+1);
  607.             for (i = 0; i < box_width; i++)
  608.               waddch(win, search_term[scroll+input_x+i] ?
  609.                             search_term[scroll+input_x+i] : ' ');
  610.             input_x = strlen(search_term) - scroll;
  611.           }
  612.           else
  613.             input_x--;
  614.           search_term[scroll+input_x] = '\0';
  615.           wmove(win, y+1, input_x + x+1);
  616.           waddch(win, ' ');
  617.           wmove(win, y+1, input_x + x+1);
  618.           wrefresh_lock(win);
  619.         }
  620.         break;
  621.       case ESC:
  622.         break;
  623.       default:
  624.         if (isprint(key))
  625.           if (scroll+input_x < MAX_LEN) {
  626.             search_term[scroll+input_x] = key;
  627.             search_term[scroll+input_x+1] = '\0';
  628.             if (input_x == box_width-1) {
  629.               scroll++;
  630.               wmove(win, y+1, x+1);
  631.               for (i = 0; i < box_width-1; i++)
  632.                 waddch(win, search_term[scroll+i]);
  633.             }
  634.             else {
  635.               wmove(win, y+1, input_x++ + x+1);
  636.               waddch(win, key);
  637.             }
  638.             wrefresh_lock(win);
  639.           }
  640.     }
  641.   }
  642.  
  643.   return -1;    /* ESC pressed */
  644. }
  645. /* End of get_search_term() */
  646.  
  647.  
  648. /*
  649.  * Print current position
  650.  */
  651. static void print_position(WINDOW *win, int height, int width)
  652. {
  653.   int fpos, percent;
  654.  
  655.   if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1)
  656.     exiterr("\nError moving file pointer in print_position().\n");
  657.  
  658.   wattrset(win, position_indicator_attr);
  659.   percent = !file_size ? 100 : ((fpos-fd_bytes_read+tabize(page-buf, 1))*100)/file_size;
  660.   wmove(win, height-3, width-9);
  661.   wprintw(win, "(%3d%%)", percent);
  662. }
  663. /* End of print_position() */
  664.  
  665. /*
  666.  * read_high() substitutes read() for tab->spaces conversion
  667.  *
  668.  * buffer_len, fd_bytes_read, bytes_read are modified
  669.  * buf is allocated
  670.  *
  671.  * fd_bytes_read is the effective number of bytes read from file
  672.  * bytes_read is the length of buf, that can be different if tab_correct
  673.  */
  674. static char *read_high(int fd, char *buf, size_t size_read) {
  675.   char *buftab, ch;
  676.   int i = 0, j, n, begin_line, tmpint, disp = 0;
  677.  
  678.   /* Allocate space for read buffer */
  679.   if ((buftab = malloc(size_read+1)) == NULL)
  680.     exiterr("\nCan't allocate memory in read_high().\n");
  681.  
  682.   if ((fd_bytes_read = read(fd, buftab, size_read)) == -1)
  683.     exiterr("\nError reading file in read_high().\n");
  684.  
  685.   buftab[fd_bytes_read] = '\0';    /* mark end of valid data */
  686.   
  687.   if (tab_correct) {
  688.   
  689.     /* calculate bytes_read by buftab and fd_bytes_read */
  690.     bytes_read=begin_line=0;
  691.     for (j=0; j < fd_bytes_read; j++)
  692.       if (buftab[j] == TAB)
  693.         bytes_read+=tab_len-((bytes_read-begin_line)%tab_len);
  694.       else if (buftab[j] == '\n') {
  695.         bytes_read++;
  696.         begin_line=bytes_read;
  697.       } else
  698.         bytes_read++;
  699.   
  700.   
  701.     if (bytes_read > buffer_len) {
  702.       if (buffer_first)
  703.         buffer_first = 0; /* disp = 0 */
  704.       else {
  705.         disp = page-buf;
  706.         free(buf);
  707.       }
  708.         
  709.       buffer_len = bytes_read;
  710.         
  711.       /* Allocate space for read buffer */
  712.       if ((buf = malloc(buffer_len+1)) == NULL)
  713.         exiterr("\nCan't allocate memory in read_high().\n");
  714.         
  715.       page=buf+disp;
  716.     }
  717.     
  718.   }
  719.   else {
  720.     if (buffer_first) {
  721.       buffer_first = 0;
  722.       
  723.       /* Allocate space for read buffer */
  724.       if ((buf = malloc(size_read+1)) == NULL)
  725.         exiterr("\nCan't allocate memory in read_high().\n");
  726.     }
  727.     
  728.     bytes_read = fd_bytes_read;
  729.   }
  730.   
  731.   j=0; begin_line=0;
  732.   while (j < fd_bytes_read)
  733.     if (((ch=buftab[j++]) == TAB) && (tab_correct)) {
  734.       tmpint=tab_len-((i-begin_line)%tab_len);
  735.       for(n = 0; n < tmpint; n++)
  736.         buf[i++]=' ';
  737.     } else {
  738.       if (ch == '\n')
  739.         begin_line=i+1;
  740.       buf[i++] = ch;
  741.     }
  742.     
  743.   buf[i] = '\0';    /* mark end of valid data */
  744.   
  745.   if (bytes_read == -1) return NULL;
  746.   else return buf;
  747. }
  748.  
  749. int tabize(int val, int pos) {
  750.   int fpos, i, count, begin_line;
  751.   char *buftab;
  752.  
  753.   if (!tab_correct) return val;
  754.  
  755.   if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1)
  756.     exiterr("\nError moving file pointer in tabize().\n");
  757.     
  758.   if ((lseek(fd, fpos-fd_bytes_read, SEEK_SET)) == -1)
  759.     exiterr("\nError moving file pointer in tabize().\n");
  760.  
  761.   /* Allocate space for read buffer */
  762.   if ((buftab = malloc(val+1)) == NULL)
  763.     exiterr("\nCan't allocate memory in tabize().\n");
  764.  
  765.   if ((read(fd, buftab, val)) == -1)
  766.     exiterr("\nError reading file in tabize().\n");
  767.  
  768.   begin_line=count=0;
  769.   for (i=0; i<val; i++) {
  770.     if (pos && count >= val) {
  771.       count=i;  /* it's the retval */
  772.       break;
  773.     }
  774.     if (buftab[i] == TAB)
  775.       count+=tab_len-((count-begin_line)%tab_len);
  776.     else if (buftab[i] == '\n') {
  777.       count++;
  778.       begin_line=count;
  779.     } else
  780.       count++;
  781.   }
  782.  
  783.   if (lseek(fd, fpos, SEEK_SET) == -1)
  784.     exiterr("\nError moving file pointer in tabize().\n");
  785.   
  786.   return count;
  787. }
  788.